]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
viewSelector: add Applications pane and search entry to Ctrl-Alt-Tab
authorDan Winship <danw@gnome.org>
Wed, 23 Feb 2011 19:21:47 +0000 (14:21 -0500)
committerDan Winship <danw@gnome.org>
Mon, 7 Mar 2011 16:15:05 +0000 (11:15 -0500)
Add Ctrl-Alt-Tab support to ViewTab, and fix the Applications pane to
scroll to track the keyboard focus.

The Windows pane can be switched to, but navigation within the pane is
not yet implemented.

https://bugzilla.gnome.org/show_bug.cgi?id=618887

data/theme/gnome-shell.css
js/ui/appDisplay.js
js/ui/overview.js
js/ui/viewSelector.js
src/st/st-scroll-view.c

index cfcec9e0aa3bfd0abedf95d420a79e3d1a028f41..526b059b5229d5368cf90303c0e7f3e809de21a3 100644 (file)
@@ -576,6 +576,10 @@ StTooltip StLabel {
     background-position: 10px 10px;
 }
 
+.app-filter:focus {
+    outline: 1px solid #aaa;
+}
+
 .dash-item-container > .app-well-app {
     padding: 4px 8px;
 }
index 0433cec007ed79b5552c52aee8f4a4fa6cd86c06..ffd49fa071df1d4e4e9343aa31fa74abec19b05a 100644 (file)
@@ -23,6 +23,7 @@ const Workspace = imports.ui.workspace;
 const Params = imports.misc.params;
 
 const MENU_POPUP_TIMEOUT = 600;
+const SCROLL_TIME = 0.1;
 
 function AlphabeticalView() {
     this._init();
@@ -67,6 +68,7 @@ AlphabeticalView.prototype = {
         let appIcon = new AppWellIcon(this._appSystem.get_app(appInfo.get_id()));
 
         this._grid.addItem(appIcon.actor);
+        appIcon.actor.connect('key-focus-in', Lang.bind(this, this._ensureIconVisible));
 
         appIcon._appInfo = appInfo;
         if (this._filterApp && !this._filterApp(appInfo))
@@ -75,6 +77,28 @@ AlphabeticalView.prototype = {
         this._apps.push(appIcon);
     },
 
+    _ensureIconVisible: function(icon) {
+        let adjustment = this.actor.vscroll.adjustment;
+        let [value, lower, upper, stepIncrement, pageIncrement, pageSize] = adjustment.get_values();
+
+        let offset = 0;
+        let vfade = this.actor.get_effect("vfade");
+        if (vfade)
+            offset = vfade.fade_offset;
+
+        if (icon.y < value + offset)
+            value = Math.max(0, icon.y - offset);
+        else if (icon.y + icon.height > value + pageSize - offset)
+            value = Math.min(upper, icon.y + icon.height + offset - pageSize);
+        else
+            return;
+
+        Tweener.addTween(adjustment,
+                         { value: value,
+                           time: SCROLL_TIME,
+                           transition: 'easeOutQuad' });
+    },
+
     setFilter: function(filter) {
         this._filterApp = filter;
         for (let i = 0; i < this._apps.length; i++)
@@ -128,6 +152,12 @@ ViewByCategories.prototype = {
             }));
 
         this._sections = [];
+
+        // We need a dummy actor to catch the keyboard focus if the
+        // user Ctrl-Alt-Tabs here before the deferred work creates
+        // our real contents
+        this._focusDummy = new St.Bin({ can_focus: true });
+        this.actor.add(this._focusDummy);
     },
 
     _scrollFilter: function(actor, event) {
@@ -166,7 +196,8 @@ ViewByCategories.prototype = {
     _addFilter: function(name, num) {
         let button = new St.Button({ label: GLib.markup_escape_text (name, -1),
                                      style_class: 'app-filter',
-                                     x_align: St.Align.START });
+                                     x_align: St.Align.START,
+                                     can_focus: true });
         this._filters.add(button, { expand: true, x_fill: true, y_fill: false });
         button.connect('clicked', Lang.bind(this, function() {
             this._selectCategory(num);
@@ -201,6 +232,14 @@ ViewByCategories.prototype = {
             this._addFilter(sections[i], i);
 
         this._selectCategory(-1);
+
+        if (this._focusDummy) {
+            let focused = this._focusDummy.has_key_focus();
+            this._focusDummy.destroy();
+            this._focusDummy = null;
+            if (focused)
+                this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
+        }
     }
 };
 
index ad02d1344373b65e43cb9ac3d68d75b157dd369b..6d86bdae0d361b78ef5a5ab1efce81513a08d383 100644 (file)
@@ -180,10 +180,10 @@ Overview.prototype = {
         this._group.add_actor(this.viewSelector.actor);
 
         this._workspacesDisplay = new WorkspacesView.WorkspacesDisplay();
-        this.viewSelector.addViewTab(_("Windows"), this._workspacesDisplay.actor);
+        this.viewSelector.addViewTab(_("Windows"), this._workspacesDisplay.actor, 'text-x-generic');
 
         let appView = new AppDisplay.AllAppDisplay();
-        this.viewSelector.addViewTab(_("Applications"), appView.actor);
+        this.viewSelector.addViewTab(_("Applications"), appView.actor, 'system-run');
 
         // Default search providers
         this.viewSelector.addSearchProvider(new AppDisplay.AppSearchProvider());
index 7e5fa272616ccd1f426b708f921d65e46ae24d96..5cad9cd529a12189b58d46fa6b2f15d831ca3f36 100644 (file)
@@ -1,6 +1,7 @@
 /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 
 const Clutter = imports.gi.Clutter;
+const Gtk = imports.gi.Gtk;
 const Mainloop = imports.mainloop;
 const Meta = imports.gi.Meta;
 const Signals = imports.signals;
@@ -15,12 +16,12 @@ const Search = imports.ui.search;
 const SearchDisplay = imports.ui.searchDisplay;
 const Tweener = imports.ui.tweener;
 
-function BaseTab(titleActor, pageActor) {
-    this._init(titleActor, pageActor);
+function BaseTab(titleActor, pageActor, name, a11yIcon) {
+    this._init(titleActor, pageActor, name, a11yIcon);
 }
 
 BaseTab.prototype = {
-    _init: function(titleActor, pageActor) {
+    _init: function(titleActor, pageActor, name, a11yIcon) {
         this.title = titleActor;
         this.page = new St.Bin({ child: pageActor,
                                  x_align: St.Align.START,
@@ -29,6 +30,14 @@ BaseTab.prototype = {
                                  y_fill: true,
                                  style_class: 'view-tab-page' });
 
+        if (this.title.can_focus) {
+            Main.ctrlAltTabManager.addGroup(this.title, name, a11yIcon);
+        } else {
+            Main.ctrlAltTabManager.addGroup(this.page, name, a11yIcon,
+                                            { proxy: this.title,
+                                              focusCallback: Lang.bind(this, this._a11yFocus) });
+        }
+
         this.visible = false;
     },
 
@@ -56,6 +65,11 @@ BaseTab.prototype = {
                          });
     },
 
+    _a11yFocus: function() {
+        this._activate();
+        this.page.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
+    },
+
     _activate: function() {
         this.emit('activated');
     }
@@ -63,19 +77,19 @@ BaseTab.prototype = {
 Signals.addSignalMethods(BaseTab.prototype);
 
 
-function ViewTab(label, pageActor) {
-    this._init(label, pageActor);
+function ViewTab(label, pageActor, a11yIcon) {
+    this._init(label, pageActor, a11yIcon);
 }
 
 ViewTab.prototype = {
     __proto__: BaseTab.prototype,
 
-    _init: function(label, pageActor) {
+    _init: function(label, pageActor, a11yIcon) {
         let titleActor = new St.Button({ label: label,
                                          style_class: 'view-tab-title' });
         titleActor.connect('clicked', Lang.bind(this, this._activate));
 
-        BaseTab.prototype._init.call(this, titleActor, pageActor);
+        BaseTab.prototype._init.call(this, titleActor, pageActor, label, a11yIcon);
     }
 };
 
@@ -101,7 +115,8 @@ SearchTab.prototype = {
                                         active; it should not exceed ~30
                                         characters. */
                                      hint_text: _("Type to search..."),
-                                     track_hover: true });
+                                     track_hover: true,
+                                     can_focus: true });
         this._text = this._entry.clutter_text;
         this._text.connect('key-press-event', Lang.bind(this, this._onKeyPress));
 
@@ -118,7 +133,9 @@ SearchTab.prototype = {
         this._searchResults = new SearchDisplay.SearchResults(this._searchSystem, this._openSearchSystem);
         BaseTab.prototype._init.call(this,
                                      this._entry,
-                                     this._searchResults.actor);
+                                     this._searchResults.actor,
+                                     _("Search"),
+                                     'edit-find');
 
         this._text.connect('text-changed', Lang.bind(this, this._onTextChanged));
         this._text.connect('activate', Lang.bind(this, function (se) {
@@ -366,8 +383,8 @@ ViewSelector.prototype = {
         }));
     },
 
-    addViewTab: function(title, pageActor) {
-        let viewTab = new ViewTab(title, pageActor);
+    addViewTab: function(title, pageActor, a11yIcon) {
+        let viewTab = new ViewTab(title, pageActor, a11yIcon);
         this._tabs.push(viewTab);
         this._tabBox.add(viewTab.title);
         this._addTab(viewTab);
index 3f7c12a75943914bc751637f6560f97e37b10c35..618648a369a1881e1e49b199b6e36ff2f2d9cdcd 100644 (file)
@@ -176,7 +176,8 @@ st_scroll_view_set_vfade (StScrollView *self,
       if (priv->vfade_effect == NULL)
         priv->vfade_effect = g_object_new (ST_TYPE_SCROLL_VIEW_FADE, NULL);
 
-      clutter_actor_add_effect (CLUTTER_ACTOR (self), CLUTTER_EFFECT (priv->vfade_effect));
+      clutter_actor_add_effect_with_name (CLUTTER_ACTOR (self), "vfade",
+                                          CLUTTER_EFFECT (priv->vfade_effect));
     }
    else
     {